home *** CD-ROM | disk | FTP | other *** search
- /* $Id$
- *
- * File cbase.c
- * Part of ChessBase utilities file format (CBUFF)
- * Author Anjo Anjewierden, anjo@swi.psy.uva.nl
- * Horst Aurisch, aurisch@informatik.uni-bonn.de
- * Purpose Manipulation of entire ChessBase databases
- * Works with GNU CC 2.4.5
- *
- * Notice Copyright (c) 1993 Anjo Anjewierden
- *
- * History 08/06/93 (Created)
- * 03/11/93 (Last modified)
- */
-
-
- /*------------------------------------------------------------
- * Directives
- *------------------------------------------------------------*/
-
- #include "cbuff.h"
-
-
- /*------------------------------------------------------------
- * Prototypes
- *------------------------------------------------------------*/
-
- static CBase allocCBase(char *);
- static void checkModeCBase(CBase, int);
- static long checkBoundsCBase(CBase, long);
-
-
- /*------------------------------------------------------------
- * Initialisation
- *------------------------------------------------------------*/
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node newCBase
- @deftypefun CBase newCBase (char *@var{name}, char *@var{mode})
- Allocates a new database and returns it. @var{name} is the name of
- the database (without the @file{.cbf} extension). The @var{mode}
- argument is similar to the second of @code{fopen}. @var{mode} can be:
- @example
- "r" @r{Open for reading}
- "a" @r{Open for appending}
- "c" @r{Open for writing, create first}
- @end example
- The @code{"c"} mode requires that a database of the given @var{name}
- does not exist, @code{"a"} can be used for both existing and new databases.
-
- The constant @code{NULL} is returned when the database cannot be opened or
- on another error.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- CBase
- newCBase(char *baseName, char *mode)
- { FILE *cbi;
- FILE *cbf;
- CBase cb;
-
- if (strcmp(mode, "r") == 0)
- { cbi = fopenExtension(baseName, "cbi", "rb", TRUE);
- cbf = fopenExtension(baseName, "cbf", "rb", TRUE);
- if (foundError())
- { reportError(stderr);
- if (cbi) fclose(cbi);
- if (cbf) fclose(cbf);
- return NULL;
- }
- cb = allocCBase(baseName);
- cb->cbi = cbi;
- cb->cbf = cbf;
- cb->mode = READ_MODE;
- } else
- if (strcmp(mode, "c") == 0)
- { cbi = fopenExtension(baseName, "cbi", "wb", FALSE);
- cbf = fopenExtension(baseName, "cbf", "wb", FALSE);
- if (foundError())
- { reportError(stderr);
- if (cbi) fclose(cbi);
- if (cbf) fclose(cbf);
- return NULL;
- }
- cb = allocCBase(baseName);
- cb->cbi = cbi;
- cb->cbf = cbf;
- cb->mode = WRITE_MODE;
- } else
- if (strcmp(mode, "a") == 0)
- { cbi = fopenExtension(baseName, "cbi", "r+b", TRUE);
- cbf = fopenExtension(baseName, "cbf", "r+b", TRUE);
- if (foundError())
- { reportError(stderr);
- if (cbi) fclose(cbi);
- if (cbf) fclose(cbf);
- return NULL;
- }
- cb = allocCBase(baseName);
- cb->cbi = cbi;
- cb->cbf = cbf;
- cb->mode = WRITE_MODE;
- fseek(cb->cbi, 0L, 0);
- cb->noGames = readLong(cb->cbi) - 1;
- fseek(cb->cbi, (cb->noGames+1)*sizeof(unsigned long), 0);
- cb->position = readLong(cb->cbi) - cb->noGames - 1;
- } else
- { fprintf(stderr, "Internal error: Opening database %s; mode (%s)?\n",
- baseName, mode);
- exit(1);
- }
-
- if (cb->mode == READ_MODE)
- { long i;
- unsigned long pos;
-
- cb->noGames = readLong(cb->cbi) - 1;
- cb->index = (unsigned long *) alloc(cb->noGames*sizeof(unsigned long));
- if (cb->index == NULL)
- { fprintf(stderr, "Could not allocate index for %s.cbi\n", baseName);
- freeCBase(cb);
- return NULL;
- }
- for (i=1; i<=cb->noGames; i++)
- { pos = readLong(cbi);
- cb->index[i-1] = pos - (i+1);
- }
- cb->position = readLong(cbi) - cb->noGames - 1;
- }
-
- return cb;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node freeCBase
- @deftypefun void freeCBase (CBase @var{cb})
- Reclaims the memory associated with the database @var{cb}.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- void
- freeCBase(CBase cb)
- { if (cb->cbf) fclose(cb->cbf);
- if (cb->cbi) fclose(cb->cbi);
- if (cb->index) unalloc(cb->index);
- unallocCharp(cb->name);
- unalloc(cb);
- }
-
-
- /*------------------------------------------------------------
- * Functions
- *------------------------------------------------------------*/
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getNoGamesCBase
- @deftypefun long getNoGamesCBase (CBase @var{cb})
- Returns the number of games in the database @var{cb}.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- long
- getNoGamesCBase(CBase cb)
- { return cb->noGames;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node exportGameCBase
- @deftypefun void exportGameCBase (CBase @var{dst}, CBase @var{src}, long @var{n})
- Exports (appends) game @var{n} from database @var{src} to the output database @var{dst}.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- void
- exportGameCBase(CBase dst, CBase src, long n)
- { CbGame cg;
- unsigned char *buf;
- long bytes;
-
- checkModeCBase(dst, WRITE_MODE);
- checkModeCBase(src, READ_MODE);
-
- if (src->index[n-1] & PHYSICALLY_DELETED)
- return;
-
- cg = newCbGame();
- if ((bytes=readCbGame(cg,src,n)) == (long) NULL)
- { reportError(stderr);
- return;
- }
- buf = (unsigned char *) alloc(bytes);
- /* Read game from source */
- fseek(src->cbf, src->index[n-1], 0);
- fread(buf, 1, bytes, src->cbf);
- /* Write number of games */
- fseek(dst->cbi, 0L, 0);
- writeLong(dst->noGames+1+1, dst->cbi);
- /* Write index in destination */
- fseek(dst->cbi, (dst->noGames+1) * sizeof(long), 0);
- writeLong(dst->position+dst->noGames+1+1, dst->cbi);
- /* Write game in destination */
- fseek(dst->cbf, dst->position, 0);
- fwrite(buf, 1, bytes, dst->cbf);
- dst->position += bytes;
- dst->noGames++;
- /* Write last position */
- writeLong(dst->position+dst->noGames+1, dst->cbi);
- freeCbGame(cg);
- unalloc(buf);
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node exportManyBase
- @deftypefun void exportManyCBase (CBase @var{dst}, CBase @var{src}, long @var{from}, long @var{to})
- Exports (appends) games from @var{from} through @var{to} from database
- @var{src} to the output database @var{dst}.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- void
- exportManyCBase(CBase dst, CBase src, long from, long to)
- { CbGame cg;
- unsigned char *buf;
- long bytes;
- long n;
- long count, inc;
-
- checkModeCBase(dst, WRITE_MODE);
- checkModeCBase(src, READ_MODE);
-
- from = checkBoundsCBase(src, from);
- to = checkBoundsCBase(src, to);
-
- cg = newCbGame();
-
- fprintf(stderr, "Writing games %ld - %ld to database %s\n",
- from, to, dst->name);
-
- n = to-from+1;
- inc = (n < 50L ? 1 : n/50L);
-
- for (n=from, count=0; n && n<=to; n++, count++)
- { if (count == inc)
- { fprintf(stderr, ".");
- count = 0;
- }
- if (src->index[n-1] & PHYSICALLY_DELETED)
- continue;
- if ((bytes=readCbGame(cg,src,n)) == (long) NULL)
- { reportError(stderr);
- fprintf(stderr, "; Game not written to database\n");
- continue;
- }
- buf = (unsigned char *) alloc(bytes);
- /* Read game from source */
- fseek(src->cbf, src->index[n-1], 0);
- fread(buf, 1, bytes, src->cbf);
- /* Write index in destination */
- fseek(dst->cbi, (dst->noGames+1) * sizeof(long), 0);
- writeLong(dst->position+dst->noGames+1+1, dst->cbi);
- /* Write game in destination */
- fseek(dst->cbf, dst->position, 0);
- fwrite(buf, 1, bytes, dst->cbf);
- dst->position += bytes;
- dst->noGames++;
- unalloc(buf);
- }
- /* Write last position, assumes
- * file pointer is correct.
- */
- writeLong(dst->position+dst->noGames+1, dst->cbi);
- /* Write number of games */
- fseek(dst->cbi, 0L, 0);
- writeLong(dst->noGames+1, dst->cbi);
- freeCbGame(cg);
-
- fprintf(stderr, "\n");
- }
-
-
- void
- reportCBase(CBase cb, FILE *fd)
- { fprintf(fd, "ChessBase database %s (%ld games)\n",
- cb->name, cb->noGames);
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node deleteGameCBase
- @deftypefun void deftypefun (CBase @var{cb}, long @var{n})
- Marks game @var{n} in the database @var{cb} for deletion. The
- game will be physically deleted when the game from @var{cb}
- is exported to another database (for example with
- @code{exportedManyCBase}).
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- void
- deleteGameCBase(CBase cb, long n)
- { checkModeCBase(cb, READ_MODE);
- if (n >= 1 && n <= cb->noGames)
- cb->index[n-1] |= PHYSICALLY_DELETED;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node deletedGameCBaseP
- @deftypefun bool deletedGameCBaseP (CBase @var{cb}, long @var{n})
- Succeeds if game @var{n} in database @var{cb} has been marked for
- deletion with @code{deleteGameCBase}. Note that this is different
- from @code{deleteGameP} (which indicates that the user has marked
- the game for deletion).
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- deletedGameCBaseP(CBase cb, long n)
- { checkModeCBase(cb, READ_MODE);
- if (n >= 1 && n <= cb->noGames)
- { if (cb->index[n-1] & PHYSICALLY_DELETED)
- return TRUE;
- }
- return FALSE;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getIndexGameCBase
- @deftypefun {unsigned long} getIndexGameCBase (CBase @var{cb}, long @var{n})
- Returns the index of game @var{n} in database @var{cb}. The index
- is the position where the game starts in the @code{.cbf} file.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- unsigned long
- getIndexGameCBase(CBase cb, long n)
- { checkModeCBase(cb, READ_MODE);
- if (n >= 1 && n <= cb->noGames)
- return cb->index[n-1] & ~PHYSICALLY_DELETED;
- return (unsigned long) NULL;
- }
-
-
- /*------------------------------------------------------------
- * Private functions
- *------------------------------------------------------------*/
-
- static CBase
- allocCBase(char *name)
- { CBase cb;
-
- cb = alloc(sizeof(struct cbase));
- cb->name = allocCharp(name);
- cb->noGames = 0;
- cb->index = NULL;
- cb->cbf = NULL;
- cb->cbi = NULL;
- cb->position = 0L;
-
- return cb;
- }
-
-
- static void
- checkModeCBase(CBase cb, int mode)
- { if (cb->mode != mode)
- { switch (mode)
- { case READ_MODE:
- fprintf(stderr, "Internal error: Database %s not opened for reading\n",
- cb->name);
- exit(1);
- return;
- case WRITE_MODE:
- fprintf(stderr, "Internal error: Database %s not opened for writing\n",
- cb->name);
- exit(1);
- return;
- default:
- fprintf(stderr, "Internal error: checkModeCBase mode = %d\n", mode);
- exit(1);
- }
- }
- }
-
-
- static long
- checkBoundsCBase(CBase cb, long n)
- { if (n < 1)
- return 1;
- if (n > cb->noGames)
- return cb->noGames;
- return n;
- }
-